package cn.com.cetccst.vpn.verdor.secportal;

import android.content.Context;
import android.content.Intent;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.UUID;

import cn.com.cetccst.vpn.verdor.AbsVpn;
import cn.com.cetccst.vpn.ErrorType;
import cn.com.cetccst.vpn.callback.ICommonCallback;
import cn.com.cetccst.vpn.callback.IGetAdServerCallback;
import cn.com.cetccst.vpn.VPNConstants;
import cn.com.westone.authclient.auth.AdAuthMethod;
import cn.com.westone.authclient.auth.CertAuthMethod;
import cn.com.westone.authclient.auth.UserPwdAuthMethod;
import cn.com.westone.authclient.bean.SSLServer;
import cn.com.westone.authclient.bean.ServerInfo;
import cn.com.westone.authclient.bean.ServerManager;
import cn.com.westone.authclient.bean.SpConfig;
import cn.com.westone.authclient.callback.Callback;
import cn.com.westone.authclient.callback.EventCallback;
import cn.com.westone.authclient.callback.GetADServerCallback;
import cn.com.westone.authclient.callback.LoginCallback;
import cn.com.westone.authclient.callback.ServerStateCallback;
import cn.com.westone.authclient.error.AuthErrno;
import cn.com.westone.authclient.secportal.SecPortalApi;

public class SecPortalVpn extends AbsVpn implements ServerStateCallback, EventCallback {

    private SecPortalApi mSecPortalApi;
    private SpConfig mSpConfig;
    private SSLServer mSSLServer;

    private LoginCallback mSPLoginCallback = new LoginCallback() {

        @Override
        public void tunnelTrustCert(String s, String s1, String s2) {
            log("login tunnelTrustCert ");
            if (mSecPortalApi != null) {
                mSecPortalApi.trustCert(VPNConstants.CERTIFICATION_TRUST_TYPE.TRUST_AND_SAVE);
            }
            if (mLoginCallback != null) {
                mLoginCallback.trustCert(s, s1, s2);
            }
        }

        @Override
        public void tunnelRequestVpn(Intent intent, int i) {
            log("login tunnelRequestVpn ");
            if (mLoginCallback != null) {
                mLoginCallback.requestVpn(intent, i);
            }
        }

        @Override
        public void onSuccess() {
            log("login success ");
            if (mLoginCallback != null) {
                mLoginCallback.onLoginSuccess();
            }
        }

        @Override
        public void onFailed(int i, String s) {
            log("login failed : " + s);
            clearServer();
            if (mLoginCallback != null) {
                mLoginCallback.onLoginFailed(getErrorType(i, s), i + ":" + s);
            }
        }
    };

    private Callback mLogoutCallback = new Callback() {
        @Override
        public void onSuccess() {
            log("logout success");
            clearServer();
            mEventStatus = VPNConstants.VPN_STATUS.VPN_STATUS_LOGOUT;
            if (mLoginCallback != null) {
                mLoginCallback.onLogoutSuccess();
            }
        }

        @Override
        public void onFailed(int i, String s) {
            log("logout failed");
            if (mLoginCallback != null) {
                mLoginCallback.onLogoutFailed(getErrorType(i, s), i + ":" + s);
            }
        }
    };

    public SecPortalVpn(Context context) {
        TAG = "SecPortalVpn";
        setServerInfo(AuthConfig.AUTH_SERVER_IP, AuthConfig.AUTH_SERVER_PORT, AuthConfig.AUTH_SERVER_ISSUE);
    }

    @Override
    public int init(Context context) {
        mContext = context;
        mSpConfig = new SpConfig();
        mSpConfig.setAlogEngine("SKFSM234");

        mSecPortalApi = SecPortalApi.getInstance();

        //todo 使用真实的deviceid
        String deviceId = UUID.randomUUID().toString();
        log("device id : " + deviceId);
        int ret = mSecPortalApi.init(context, deviceId, mSpConfig);
        return ret;
    }

    @Override
    public void prepare() {
        if (mSecPortalApi != null) {
            mSecPortalApi.prepareVpn(mContext);
        }
    }

    @Override
    public void setPinCode(String pinCode) {
        mPinCode = pinCode;
    }

    private SSLServer getServer() {
        if (mSSLServer == null) {
            initServer();
        }
        return mSSLServer;
    }

    @Override
    protected void initServer() {
        try {
            ServerInfo serverInfo = new ServerInfo();
            serverInfo.setServerAddr(mServerAddr);
            serverInfo.setServerPort(mPort);
            serverInfo.setAlias(mAlias);

            mSSLServer = new SSLServer(serverInfo);
            mSSLServer.setEventCallback(this);
            mSSLServer.setServeStateChangeCallback(this);

        } catch (Exception e) {
            log("can not init server", e);
        }
    }

    /**
     * 这个方法正常是要将VPN SDK的错误码 mapping为 {@link VPNConstants.VPN_STATUS} 中的code
     * 但是目前只有 SecPortal 一个VPN SDN，错误码也和其一致，所以此处不做处理，直接返回即可。
     */
    @Override
    protected int mappingCode(int code) {
        return code;
    }

    @Override
    protected int getErrorType(int code, String message) {
        switch (code) {
            case AuthErrno.AUTH_USER_PWD_RECV_RESPONSE_FAILED:
            case AuthErrno.WAC_UI_LOGIN_AUTH_PASSWORD_ERROR:
                return ErrorType.ERROR_PWD;
            case AuthErrno.AUTH_LOGIN_RESET_PWD:
                return ErrorType.ERROR_RESET_PWD;
            //-302:TF卡:登录口令不正确!
            case -302:
                return ErrorType.ERROR_TF_PWD;
            case AuthErrno.WAC_UI_LOGIN_AUTH_AD_DOMAIN_RECV_RESPONSE_FAILED:
                return ErrorType.ERROR_AD_DOMAIN_RECV_RESP;
            case AuthErrno.AUTH_CONNECT_SERVER_FAILED:
            case AuthErrno.AUTH_GET_DESKTOP_LIST_ERROR:
                return ErrorType.ERROR_SERVER;
        }
        if (code == AuthErrno.WAC_UI_LOGIN_AUTH_ACCOUNT_LOCKED || message.contains("锁定")) {
            return ErrorType.ERROR_AUTH_LOCKED;
        }
        return ErrorType.ERROR_OTHERS;
    }

    @Override
    public int getEventStatus() {
        log("the server status is : " + mEventStatus);
        return mEventStatus;
    }

    @Override
    public int getServerStatus() {
        return mServerStatus;
    }

    @Override
    public void updateServerInfo(String addr, int port, String alias) {
        log(String.format(Locale.ENGLISH, "update server info to [addr:%s,port:%d,alias:%s] ", addr, port, alias));
        setServerInfo(addr, port, alias);
    }

    @Override
    public boolean isVPNAlreadyLogin() {
        return mServerStatus == VPNConstants.VPN_STATUS.VPN_STATUS_CONNECTED;
    }

    @Override
    public String getRunLogPath() {
        if (mSecPortalApi != null) {
            return mSecPortalApi.getRunLogPath();
        }

        return "";
    }

    @Override
    public void loginByUserName(String userName, String pwd) {
        log("login by user : " + userName + " / " + pwd);
        if (valideServerInfo() && valideArgs(userName, pwd)) {
            if (getServer() != null) {
                UserPwdAuthMethod userPwdAuthMethod = new UserPwdAuthMethod();
                userPwdAuthMethod.setUserName(userName); //设置用户名
                userPwdAuthMethod.setPassword(pwd); //设置密码
                getServer().login(userPwdAuthMethod, mSPLoginCallback);
            }
        }
    }

    //default pin is 11111111
    @Override
    public void loginByCert(String pin) {

        if (valideServerInfo() && valideArgs(pin)) {
            if (getServer() != null) {
                CertAuthMethod certAuthMethod = new CertAuthMethod();
                certAuthMethod.setKeyPin(pin);
                log("login");
                getServer().login(certAuthMethod, mSPLoginCallback);
            }
        }
    }

    @Override
    public void loginByAd(String server, String userName, String pwd) {
        if (valideServerInfo() && valideArgs(server, userName, pwd)) {
            if (getServer() != null) {
                AdAuthMethod adAuthMethod = new AdAuthMethod();
                adAuthMethod.setAdAddress(server);
                adAuthMethod.setAdUserName(userName);
                adAuthMethod.setAdPassword(pwd);
                getServer().login(adAuthMethod, mSPLoginCallback);
            }
        }
    }

    @Override
    public void loginIpsec(String pin) {
        //not suppport
    }

    @Override
    public void loginUas(String userName, String pwd) {
        //not suppport
    }

    @Override
    public void logout() {
        log("logout");
        if (getServer() != null) {
            getServer().logout(mLogoutCallback);
        }

    }

    @Override
    public void changeUserPwd(String userName, String oldPwd, String newPwd, ICommonCallback callback) {
        if (getServer() != null && mSecPortalApi != null) {
            mSecPortalApi.changeUserPwd(getServer().getServerId(), userName, oldPwd, newPwd, new Callback() {
                @Override
                public void onSuccess() {
                    Log.i(TAG, "changeUserPwd onSuccess");
                    if (callback != null) {
                        callback.onSuccess();
                    }
                }

                @Override
                public void onFailed(int i, final String s) {
                    Log.i(TAG, "changeUserPwd onFailed :" + s);
                    if (callback != null) {
                        callback.onFailed(i, s);
                    }
                }
            });
        }
    }

    @Override
    public void changePinPwd(String oldPwd, String newPwd, ICommonCallback callback) {
        if (getServer() != null) {
            mSecPortalApi.changePinPwd(oldPwd, newPwd, new Callback() {
                @Override
                public void onSuccess() {
                    Log.i(TAG, "changeUserPwd onSuccess");
                    if (callback != null) {
                        callback.onSuccess();
                    }
                }

                @Override
                public void onFailed(int i, final String s) {
                    Log.i(TAG, "changeUserPwd onFailed :" + s);
                    if (callback != null) {
                        callback.onFailed(i, s);
                    }
                }
            });
        }
    }

    @Override
    public void enableWhiteListApp(boolean enable) {
        if (mSpConfig != null) {
            mSpConfig.enableWhiteApp(enable);
        }
    }

    @Override
    public void setWhiteAppList(List<String> packages) {
        if (mSpConfig != null && packages != null) {
            mSpConfig.setWhiteAppList(packages);
        }
    }

    @Override
    public void setInternetWhiteApp(String packageName) {
        if (mSecPortalApi != null) {
            mSecPortalApi.setInternetWhiteApp(packageName);
        }
    }

    @Override
    public void getAdServer(IGetAdServerCallback callback) {
        mSecPortalApi.getADServer(new GetADServerCallback() {
            @Override
            public void onGetADSuccess(ArrayList<String> arrayList) {
                if (callback != null) {
                    callback.onGetAdServerSuccess(arrayList);
                }
            }

            @Override
            public void onGetADFailed(String s, int i) {
                if (callback != null) {
                    callback.onGetAdServerFailed(i, s);
                }
            }
        }, getServer().getServerId());
    }

    @Override
    public List<String> getWhiteAppList() {
        if (mSpConfig != null) {
            mSpConfig.getWhiteAppList();
        }
        return new ArrayList<>();
    }

    @Override
    public void serverState(int i) {
        int status;
        switch (i) {
            case 1:
                status = VPNConstants.VPN_STATUS.VPN_STATUS_CONNECTED;
                break;
            case 2:
                status = VPNConstants.VPN_STATUS.VPN_STATUS_CONNECTING;
                break;
            default:
                status = VPNConstants.VPN_STATUS.VPN_STATUS_PENDING;
        }
        mServerStatus = status;
        if (mServerStatusCallback != null) {
            mServerStatusCallback.onServerStatus(status);
        }

    }

    @Override
    public void eventCallback(int i) {
        event(i);
    }

    private void clearServer() {
        mSSLServer = null;
        ServerManager.getServerManagerInstance().clearServerList();
    }
}
